// Copyright (c) 2020 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

/**
*@describe:
*@author wfl19/Kristas
*@date 2021/08/28
 */

package swagger_plugin

import (
	"gitee.com/kristas/booting-go/framework/common/util/reflectx"
	"github.com/savaki/swag/endpoint"
	"github.com/savaki/swag/swagger"
	"reflect"
)

var typeMapping = map[reflect.Kind]string{
	reflect.Invalid:    "string",
	reflect.Bool:       "boolean",
	reflect.Int:        "integer",
	reflect.Int8:       "integer",
	reflect.Int16:      "integer",
	reflect.Int32:      "integer",
	reflect.Int64:      "integer",
	reflect.Uint:       "integer",
	reflect.Uint8:      "integer",
	reflect.Uint16:     "integer",
	reflect.Uint32:     "integer",
	reflect.Uint64:     "integer",
	reflect.Uintptr:    "integer",
	reflect.Float32:    "number",
	reflect.Float64:    "number",
	reflect.Complex64:  "number",
	reflect.Complex128: "number",
	reflect.Array:      "array",
	reflect.Interface:  "string",
	reflect.Map:        "object",
	reflect.Slice:      "array",
	reflect.String:     "string",
	reflect.Struct:     "object",
}

func endpointHeader(name, typ, description string, required bool) endpoint.Option {
	p := swagger.Parameter{
		Name:        name,
		In:          "header",
		Type:        typ,
		Description: description,
		Required:    required,
	}
	return endpointParameter(p)
}

func endpointHeaderType(name string, t reflect.Type, description string) endpoint.Option {
	var required = true
	if t.Kind() == reflect.Ptr {
		t = t.Elem()
		required = false
	}
	return endpointHeader(name, typeMapping[t.Kind()], description, required)
}

func endpointPathBody(t reflect.Type) []endpoint.Option {
	params := make([]endpoint.Option, 0)
	reflectx.ForEachField(reflect.New(t).Interface(), false, func(field reflect.StructField, value reflect.Value) error {
		params = append(params, endpointPathType(field.Type, field.Tag.Get("json"), ""))
		return nil
	})
	return params
}

func endpointPathType(t reflect.Type, name, description string) endpoint.Option {
	var required = true
	if t.Kind() == reflect.Ptr {
		t = t.Elem()
		required = false
	}
	return endpoint.Path(name, typeMapping[t.Kind()], description, required)
}

func endpointQueryBody(t reflect.Type) []endpoint.Option {
	params := make([]endpoint.Option, 0)
	reflectx.ForEachField(reflect.New(t).Interface(), false, func(field reflect.StructField, value reflect.Value) error {
		params = append(params, endpointQueryType(field.Type, field.Tag.Get("json"), ""))
		return nil
	})
	return params
}

func endpointQueryType(t reflect.Type, name, description string) endpoint.Option {
	var required = true
	if t.Kind() == reflect.Ptr {
		t = t.Elem()
		required = false
	}
	return endpoint.Query(name, typeMapping[t.Kind()], description, required)
}

func endpointParameter(p swagger.Parameter) endpoint.Option {
	return func(b *endpoint.Builder) {
		if b.Endpoint.Parameters == nil {
			b.Endpoint.Parameters = []swagger.Parameter{}
		}
		b.Endpoint.Parameters = append(b.Endpoint.Parameters, p)
	}
}
